package com.runa.monitor.platinterface.netservice.handler;

import com.alibaba.fastjson.JSON;
import com.runa.monitor.platinterface.base.BaseContainer;
import com.runa.monitor.platinterface.netservice.equipment.NetEqu;
import com.runa.monitor.platinterface.platService.NetEquService;
import com.runa.persistence.util.LogUtil;
import com.runa.persistence.util.SpringContextUtil;
import com.runa.rccprotocol.dto.ConcentratorResponseData;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelId;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import org.apache.pulsar.shade.io.netty.channel.socket.DatagramChannel;

import java.io.IOException;

/**
 * @author zhuj
 */
@Slf4j
@ChannelHandler.Sharable
public class RccResponseHandler extends SimpleChannelInboundHandler<ConcentratorResponseData<byte[]>> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ConcentratorResponseData msg) {
        if (msg.getAck() != null) {
            ctx.channel().writeAndFlush(msg.getAck());
        }
        NetEqu<String > netEqu = null;
        NetEquService netEquService = SpringContextUtil.getBean(NetEquService.class);
        if (msg.getAddress() == null) {
            Object serial = NetEqu.getSerial(ctx.channel().id().asLongText());
            if (serial != null) {
                netEqu = netEquService.getNetEquBySerialCache((String) serial);
            }
            if (msg.isUpward()) {
                netEqu = netEquService.getEeee();
            }
        } else {
            //若是主动上报，需要每次重新注册链接
            netEqu = netEquService.getNetEquBySerialCache(msg.getAddress());
            if (msg.isUpward()) {
                if (netEqu == null) {
                    netEqu = netEquService.getNetEquBySerial(msg.getAddress());
                }
                if (netEqu != null) {
                    netEqu.register(ctx.channel());
                }
            }
        }
        if (netEqu != null) {
            netEqu.receive(msg);
        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        try {
            String channelId = ctx.channel().id().asLongText();
            Object serial = NetEqu.getSerial(channelId);
            log.info("{} > channel break: {} ", channelId, serial );
            if (serial != null) {
                LogUtil.info((String)serial, "掉线, channelId: {}", channelId);
                BaseContainer.netStatusCallback().rccStatusChange(String.valueOf(serial), false);
            }
        } catch (Exception e) {
            log.error("channel break error: ", e);
        }
        super.channelInactive(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ChannelId channelId = ctx.channel().id();
        Object serial = NetEqu.getSerial(channelId.asLongText());
        log.error("{} ResponseHandler exceptionCaught: ", serial, cause);
        if (cause instanceof IOException) {
            LogUtil.info((String)serial, "exceptionCaught 关闭channel: {}", channelId);
            ctx.close();
        }
        super.exceptionCaught(ctx, cause);
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        ChannelId channelId = ctx.channel().id();
        Object serial = NetEqu.getSerial(channelId.asLongText());
        log.error("{} ResponseHandler userEventTriggered", serial);
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            switch (event.state()) {
                case READER_IDLE:
                case WRITER_IDLE:
                case ALL_IDLE:
                    if (ctx.channel() instanceof NioSocketChannel &&
                            NetEqu.getSerial(ctx.channel().id().asLongText()) == null) {
                        LogUtil.info((String)serial, "userEventTriggered 关闭channel: {}, event state: {}", channelId, event.state());
                        ctx.close();
                    }
            }
        }
        super.userEventTriggered(ctx, evt);
    }
}
